using System;
using Microsoft.SPOT;
using Gadgeteer.Interfaces.Timed;

namespace Gadgeteer.Interfaces
{
    /// <summary>
    /// Call ServiceLocator.Locator.Setup (should be an extension method) to before using the locator.
    /// </summary>
    public class ServiceLocator
    {
        internal static void ThrowSetupIfNull(object value)
        {
            if (value == null) throw new InvalidOperationException("Call ServiceLocator.Locator.Setup (should be an extension method) to before using the locator.");
        }

        private static readonly ServiceLocatedFactories _factories = new ServiceLocatedFactories();
        public static ServiceLocatedFactories Factories
        {
            get { return _factories; }
        }

        private static readonly ServiceLocator _locator = new ServiceLocator();
        public static ServiceLocator Locator
        {
            get { return _locator; }
        }

        private ServiceLocator()
        {
        }

        public static void Setup(ITimerFactory value, ILogger logger, IClock clock)
        {
            Factories.Timer = value;
            Locator._logger = logger;
            Locator._clock = clock;
        }

        private ILogger _logger;
        public ILogger Logger
        {
            get
            {
                ThrowSetupIfNull(_logger);
                return _logger;
            }
        }

        private IClock _clock;
        public IClock Clock
        {
            get
            {
                ThrowSetupIfNull(_clock);
                return _clock;
            }
        }

        public class ServiceLocatedFactories
        {
            internal ServiceLocatedFactories()
            {
            }

            private ITimerFactory _timer;
            public ITimerFactory Timer
            {
                get
                {
                    ThrowSetupIfNull(_timer);
                    return _timer;
                }
                internal set
                {
                    if (value == null) throw new ArgumentNullException("value");
                    _timer = value;
                }
            }
        }
    }
}
